#include "Mesh.hpp"
#include "MeshAlgorithm.hpp"
#include "ObjFile.hpp"
#include <fstream>
#include <sstream>

using namespace std;
void ObjFile::Write(const std::string& aFileName,
                    Mesh&              aMesh,
                    bool               aOutputMaterials)
{
   MeshAlgorithm::OrientMaterial(aMesh, 3);
   std::vector<bool> needsSwap(aMesh.faces.size(), false);
   ofstream file(aFileName.c_str());

   for (size_t i = 0; i < aMesh.faces.size(); ++i)
   {
      Face& f = aMesh.faces[i];
      if (f.materials[0] > f.materials[1])
      {
         needsSwap[i] = true;
      }
   }

   for (size_t i = 0; i < aMesh.verts.size(); ++i)
   {
      Vec3& v = aMesh.verts[i];
      file << "v " << v.x << ' ' << v.y << ' ' << v.z << '\n';
   }
   for (size_t i = 0; i < aMesh.faces.size(); ++i)
   {
      Face& f = aMesh.faces[i];
      if (needsSwap[i])
      {
         file << "f " << f.vertex[2]+1 << ' ' << f.vertex[1]+1 << ' ' << f.vertex[0]+1 << '\n';
      }
      else
      {
         file << "f " << f.vertex[0]+1 << ' ' << f.vertex[1]+1 << ' ' << f.vertex[2]+1 << '\n';
      }
   }
   if (aOutputMaterials)
   {
      file << "bind m face\n";
      for (size_t i = 0; i < aMesh.faces.size(); ++i)
      {
         Face& f = aMesh.faces[i];
         if (needsSwap[i])
         {
            file << "m " << f.materials[1] << " " << f.materials[0] << "\n";
         }
         else
         {
            file << "m " << f.materials[0] << " " << f.materials[1] << "\n";
         }
      }
   }
}

void ObjFile::Read(const std::string& aFileName,
                   Mesh&              aMesh)
{
   aMesh.faces.clear();
   aMesh.verts.clear();
   ifstream file(aFileName.c_str());
   char line[256];
   int   bindIndex = 0;
   while (file.getline(line, 255))
   {
      if (line[0] == '#') continue;
      if (line[0] == 'v' && line[1] == ' ')
      {
         Vec3 v;
         sscanf(line+1,"%f %f %f", &v.x, &v.y, &v.z);
         aMesh.verts.push_back(v);
      }
      if (line[0] == 'f' && line[1] == ' ')
      {
         Face f;
         int quadVert(0);
         int vertCount = sscanf(line+1,"%i %i %i %i", &f.vertex[0], &f.vertex[1], &f.vertex[2], &quadVert);
         --f.vertex[0];
         --f.vertex[1];
         --f.vertex[2];
         f.materials[0] = f.materials[1] = 0;
         aMesh.faces.push_back(f);
         if (vertCount == 4)
         {
            f.vertex[1] = f.vertex[0];
            f.vertex[0] = quadVert-1;
            aMesh.faces.push_back(f);
         }
      }
      if (line[0] == 'm' && line[1] == ' ')
      {
         int m1, m2;
         sscanf(line+1,"%i %i", &m1, &m2);
         Face& f = aMesh.faces[bindIndex++];
         f.materials[0] = m1;
         f.materials[1] = m2;
      }
   }
   //MeshAlgorithm::MakeManifold(aMesh);
}
